using System.IO;
using UnityEditor;
using UnityEngine;

namespace AssetTool
{
    public partial class UIAssetTool
    {
        public enum ScaleType
        {
            /// <summary>
            /// 最近
            /// </summary>
            Nearest,

            /// <summary>
            /// 最近并保持尺寸
            /// </summary>
            NearestKeepRatio,

            /// <summary>
            /// 较小
            /// </summary>
            Smaller,

            /// <summary>
            /// 较大
            /// </summary>
            Bigger,
        }

        private static ScaleType curType = ScaleType.NearestKeepRatio;

        private delegate void ImplAction(Texture2D tex);

        /// <summary>
        /// 把NPOT的纹理改为POT.
        /// 用于处理UI单图.
        /// </summary>
        [MenuItem("Assets/UITextureTool/贴图保持比例缩放为Nearest POT", priority = 1)]
        public static void ScaleToPotNearestKeepRatio()
        {
            curType = ScaleType.NearestKeepRatio;
            DoScale();
        }

        [MenuItem("Assets/UITextureTool/贴图缩放为Nearest POT", priority = 4)]
        public static void ScaleToNearestPot()
        {
            curType = ScaleType.Nearest;
            DoScale();
        }

        [MenuItem("Assets/UITextureTool/贴图缩放为Bigger POT", priority = 2)]
        public static void ScaleToPotBigger()
        {
            curType = ScaleType.Bigger;
            DoScale();
        }

        [MenuItem("Assets/UITextureTool/贴图缩放为Smaller POT", priority = 3)]
        public static void ScaleToPotSmaller()
        {
            curType = ScaleType.Smaller;
            DoScale();
        }

        private static void DoScale()
        {
            var objs = Selection.objects;
            foreach (var itr in objs)
            {
                if (itr is Texture2D tex)
                {
                    int oldWidth = tex.width;
                    int oldHeight = tex.height;

                    if (curType == ScaleType.NearestKeepRatio)
                    {
                        ConvertTextureToPotKeepRatio(tex);
                    }
                    else
                    {
                        ConvertTextureToPot(tex);
                    }
                    Debug.LogWarning($"{tex.name} is scaled from [{oldWidth}.{oldHeight}] to [{tex.width},{tex.height}]");
                }
            }
        }

        /// <summary>
        /// 保持比例并缩放到Nearest
        /// </summary>
        /// <param name="oldTex"></param>
        private static void ConvertTextureToPotKeepRatio(Texture2D oldTex)
        {
            if (Mathf.IsPowerOfTwo(oldTex.width) && Mathf.IsPowerOfTwo(oldTex.height))
            {
                //都是POT了, 不处理
                return;
            }

            var path = AssetDatabase.GetAssetPath(oldTex);

            //打开Texture的Readable
            var importer = (TextureImporter)AssetImporter.GetAtPath(path);
            importer.isReadable = true;

            //部分压缩格式导致无法转换, 先转成不压缩, 然后再还原.
            var oldSettings = importer.GetDefaultPlatformTextureSettings();
            var cachedOldSettings = new TextureImporterPlatformSettings();
            oldSettings.CopyTo(cachedOldSettings);
            oldSettings.textureCompression = TextureImporterCompression.Uncompressed;
            importer.SetPlatformTextureSettings(oldSettings);
            importer.SaveAndReimport();

            //1. 计算新尺寸
            //原始尺寸
            int oldWidth = oldTex.width;
            int oldHeight = oldTex.height;
            float ratio = (float)oldWidth / oldHeight;

            //Scale后的有效尺寸(保持比例)
            int newFillWidth = 0;
            int newFillHeight = 0;

            //Scale后的Texture尺寸
            int newTexWidth = 0;
            int newTexHeight = 0;

            if (ratio > 1f)
            {
                //宽比高大
                newTexWidth = Mathf.ClosestPowerOfTwo(oldWidth);
                newFillWidth = newTexWidth;
                newFillHeight = Mathf.FloorToInt(newTexWidth / ratio);
                newTexHeight = Mathf.NextPowerOfTwo(newFillHeight);
            }
            else
            {
                //高比宽大
                newTexHeight = Mathf.ClosestPowerOfTwo(oldHeight);
                newFillHeight = newTexHeight;
                newFillWidth = Mathf.FloorToInt(newTexHeight * ratio);
                newTexWidth = Mathf.NextPowerOfTwo(newFillWidth);
            }

            //Debug.Log($"Old:[{oldWidth},{oldHeight}]=>Fill:[{newFillWidth},{newFillHeight}]=>Tex:[{newTexWidth},{newTexHeight}]");

            //2. 从OldTexture生成FillTexture, 保持比例缩放, 但不是完全的POT
            var fillTex = ScaleTexture(oldTex, newFillWidth, newFillHeight);

            //3. 把FillTexture填入Pot Texture
            Texture2D potTex = new Texture2D(newTexWidth, newTexHeight, TextureFormat.RGBA32, false);

            Vector4 spriteBoarder;
            var emptyColor = new Color(0, 0, 0, 0);
            if (ratio > 1f)
            {
                //更宽
                int startHeight = (newTexHeight - newFillHeight) / 2;
                int endHeight = newTexHeight - startHeight - 1;
                for (int i = 0; i < newTexWidth; i++)
                {
                    for (int j = 0; j < newTexHeight; j++)
                    {
                        if (j >= startHeight && j <= endHeight)
                        {
                            //Fill
                            potTex.SetPixel(i, j, fillTex.GetPixel(i, j - startHeight));
                        }
                        else
                        {
                            //Empty
                            potTex.SetPixel(i, j, emptyColor);
                        }
                    }
                }
                spriteBoarder = new Vector4(0, startHeight, 0, startHeight);
            }
            else
            {
                //更高
                int startWidth = (newTexWidth - newFillWidth) / 2;
                int endWidth = newTexWidth - startWidth - 1;
                for (int i = 0; i < newTexWidth; i++)
                {
                    for (int j = 0; j < newTexHeight; j++)
                    {
                        if (i >= startWidth && i < endWidth)
                        {
                            //Fill
                            potTex.SetPixel(i, j, fillTex.GetPixel(i - startWidth, j));
                        }
                        else
                        {
                            //Empty
                            potTex.SetPixel(i, j, emptyColor);
                        }
                    }
                }
                spriteBoarder = new Vector4(startWidth, 0, startWidth, 0);
            }

            potTex.Apply();
            SaveTextureToFile(potTex, path);

            //关闭Texture的Readable
            importer = (TextureImporter)AssetImporter.GetAtPath(path);
            importer.isReadable = false;
            importer.textureType = TextureImporterType.Sprite;

            //选择Simple模式,不需要boarder
            //importer.spriteImportMode = SpriteImportMode.Single;
            //importer.spriteBorder = spriteBoarder;
            cachedOldSettings.crunchedCompression = true;
            importer.SetPlatformTextureSettings(cachedOldSettings);
            importer.SaveAndReimport();
        }

        /// <summary>
        /// 修改比例按类型缩放
        /// </summary>
        /// <param name="tex"></param>
        private static void ConvertTextureToPot(Texture2D tex)
        {
            if (Mathf.IsPowerOfTwo(tex.width) && Mathf.IsPowerOfTwo(tex.height))
            {
                //都是POT了, 不处理
                return;
            }

            var path = AssetDatabase.GetAssetPath(tex);

            //打开Texture的Readable
            var importer = (TextureImporter)AssetImporter.GetAtPath(path);
            importer.isReadable = true;

            //部分压缩格式导致无法转换, 先转成不压缩, 然后再还原.
            var oldSettings = importer.GetDefaultPlatformTextureSettings();
            var cachedOldSettings = new TextureImporterPlatformSettings();
            oldSettings.CopyTo(cachedOldSettings);
            oldSettings.textureCompression = TextureImporterCompression.Uncompressed;
            importer.SetPlatformTextureSettings(oldSettings);
            importer.SaveAndReimport();

            int newWidth = 0;
            int newHeight = 0;
            switch (curType)
            {
                case ScaleType.Nearest:
                    {
                        newWidth = Mathf.ClosestPowerOfTwo(tex.width);
                        newHeight = Mathf.ClosestPowerOfTwo(tex.height);
                    }
                    break;

                case ScaleType.Bigger:
                    {
                        newWidth = Mathf.NextPowerOfTwo(tex.width);
                        newHeight = Mathf.NextPowerOfTwo(tex.height);
                    }
                    break;

                case ScaleType.Smaller:
                    {
                        newWidth = Mathf.NextPowerOfTwo(tex.width) / 2;
                        newHeight = Mathf.NextPowerOfTwo(tex.height) / 2;
                    }
                    break;
            }

            tex = ScaleTexture(tex, newWidth, newHeight);
            SaveTextureToFile(tex, path);

            //关闭Texture的Readable
            importer = (TextureImporter)AssetImporter.GetAtPath(path);
            importer.isReadable = false;
            cachedOldSettings.crunchedCompression = true;
            importer.SetPlatformTextureSettings(cachedOldSettings);
            importer.SaveAndReimport();
        }

        /// <summary>
        /// Texture缩放到指定的尺寸
        /// </summary>
        /// <param name="source"></param>
        /// <param name="targetWidth"></param>
        /// <param name="targetHeight"></param>
        /// <returns></returns>
        private static Texture2D ScaleTexture(Texture2D source, int targetWidth, int targetHeight)
        {
            Texture2D result = new Texture2D(targetWidth, targetHeight, source.format, false);
            float incX = (1.0f / (float)targetWidth);
            float incY = (1.0f / (float)targetHeight);
            for (int i = 0; i < result.height; ++i)
            {
                for (int j = 0; j < result.width; ++j)
                {
                    Color newColor = source.GetPixelBilinear((float)j / (float)result.width, (float)i / (float)result.height);
                    result.SetPixel(j, i, newColor);
                }
            }
            result.Apply();
            return result;
        }

        /// <summary>
        /// 把Texture保存为png文件
        /// </summary>
        /// <param name="texture"></param>
        /// <param name="fileName"></param>
        private static void SaveTextureToFile(Texture2D texture, string fileName)
        {
            var filePath = Path.Combine(Application.dataPath.Replace("/Assets", string.Empty), fileName);
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            using (var file = File.Open(filePath, FileMode.Create))
            {
                texture.EncodeToPNG();
                var buffer = new BinaryWriter(file);
                buffer.Write(texture.EncodeToPNG());
            }
            return;
        }
    }
}